import 'dart:async';

import 'package:bike_ride/api/cmd_repository.dart';
import 'package:bike_ride/api/common_repository.dart';
import 'package:bike_ride/api/req.dart';
import 'package:bike_ride/common/mvvm/base_view_model.dart';
import 'package:bike_ride/common/net/dio_client.dart';
import 'package:bike_ride/common/net/dio_response.dart';
import 'package:bike_ride/common/util/account_manager.dart';
import 'package:bike_ride/common/util/debouncer.dart';
import 'package:bike_ride/common/util/google_map_utils.dart';
import 'package:bike_ride/common/widget/notifier_widget.dart';
import 'package:bike_ride/generated/l10n.dart';
import 'package:bike_ride/model/cyling/model/bike_real_time_m.dart';
import 'package:bike_ride/model/cyling/model/borrow_bike_m.dart';
import 'package:bike_ride/model/cyling/model/unpay_info_m.dart';
import 'package:bike_ride/model/cyling/view/cyling_v.dart';
import 'package:bike_ride/model/unlock/model/bike_info_m.dart';
import 'package:bike_ride/res/global/globals.dart';
import 'package:bike_ride/res/style/color_styles.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';

class CyclingViewModel extends PageViewModel<CyclingViewState> {
  CancelToken? cancelToken;

  // 地图控制器
  final Completer<GoogleMapController> mapController =
      Completer<GoogleMapController>();
  ImageConfiguration devicePixelRatio =
      const ImageConfiguration(devicePixelRatio: 2);

  final double mapZoom = 18;

  // 地图标记、路线规划
  Set<Marker> markers = {};
  Set<Marker> stationMarkers = {};
  Set<Polygon> stationPolygons = {};
  Set<Polygon> areaPolygons = {};
  Set<Polyline> polyLines = {};

  //0:还车站点 1：禁停区，2：禁行区，3：扣车区,4：接客站点
  late BitmapDescriptor normalStationIcon;
  late BitmapDescriptor forbidStationIcon;
  late BitmapDescriptor noWaitStationIcon;
  late BitmapDescriptor lockStationIcon;

  bool isRequestingVehicle = false;
  BikeInfoM? bikeInfoM;
  BikeRealTimeM? bikeRealTimeM;

  UnPayInfoM? unPayInfoM;
  BorrowBikeM? borrowBikeM;
  Response? tempLockBikeM;
  Response? returnBikeM;
  Response? helmetUnlockM;

  /// 开锁、临时锁车倒计时（serverTime - startTime）
  final unLockCountdownTime = ValueNotifier<num>(0);
  final tempLockCountdownTime = ValueNotifier<num>(0);

  final bikeStatus = ValueNotifier<BikeStatus>(BikeStatus.riding);

  String? vid;
  String? orderId;
  /// 是否开启先付款后还车
  bool isOpenPrepayEndOrder = false;

  @override
  onCreate() {
    cancelToken = CancelToken();
    pageDataModel = PageDataModel();

    isOpenPrepayEndOrder = AccountManager.areaInfoM?.isOpenPrepayEndOrder == 1;
    /// 根据vid获取orderId,根据orderId获取vid
    final argument = state.widget.arguments;
    if (argument['vid'] != null) {
      vid = argument['vid'];
      borrowBike(vid!).then((value){
        getBikeInfo(vid!);
      });
      getBikeInfo(vid!);
    } else if (argument['order_id'] != null) {
      orderId = argument['order_id'];
      bikeStatus.value = BikeStatus.riding;
      getUnPayInfo(orderId!).then((value) {
        if (unPayInfoM?.vid != null) {
          vid = unPayInfoM!.vid!;
          getBikeInfo(vid!);
        }
      });
    }
    initBitmap();
    getBrandAreaInfo();
  }

  Future initBitmap() async {
    BitmapDescriptor.fromAssetImage(
            devicePixelRatio, 'assets/images/stop_icon1.png',
            mipmaps: false)
        .then((value) {
      normalStationIcon = value;
    });
    BitmapDescriptor.fromAssetImage(
            devicePixelRatio, 'assets/images/stop_icon2.png',
            mipmaps: false)
        .then((value) {
      forbidStationIcon = value;
      lockStationIcon = value;
    });
    BitmapDescriptor.fromAssetImage(
            devicePixelRatio, 'assets/images/stop_icon11.png',
            mipmaps: false)
        .then((value) {
      noWaitStationIcon = value;
    });
  }

  @override
  onDispose() {
    if (!(cancelToken?.isCancelled ?? true)) {
      cancelToken?.cancel();
    }
    super.onDispose();
  }

  Future getServerTime() async {
    final result =
        await CommonRepository.getServerTimeIdl(cancelToken: cancelToken);
    if (result != null) {
      unLockCountdownTime.value = result.timestamp! - (unPayInfoM?.openTime??0);
      tempLockCountdownTime.value = result.timestamp! - (unPayInfoM?.temporaryParkingLockTime??0);
      //state.notifyChange();
    }
  }

  Future getOrderNoExist() async {
    final result =
        await CommonRepository.getOrderNoExistIdl(cancelToken: cancelToken,vid: vid!);
    if(result){
      EasyLoading.showToast('订单已结束');
      state.navigatorToPay();
    }
  }

  Future<BorrowBikeM> borrowBike(String vid) async {
    bikeStatus.value = BikeStatus.unLocking;
    final result = await CommonRepository.borrowBikeIdl(
        cancelToken: cancelToken,
        vid: vid,
        lat: AccountManager.userLatitude!,
        lng: AccountManager.userLongitude!);
    borrowBikeM = result;
    if (result.errorMsg == null) {
      orderId = result.orderId!;
      bikeStatus.value = BikeStatus.riding;

      unLockCountdownTime.value = 0;
      getUnPayInfo(result.orderId);
    }else{
      bikeStatus.value = BikeStatus.unLockFailed;
    }
    return result;
  }

  Future<Response> tempLockBike(String vid,String orderId,int sw) async {
    if(sw ==1){
      bikeStatus.value = BikeStatus.tempLocking;
      EasyLoading.show();
    }else{
      EasyLoading.show(status: '开锁中');
    }
    final Response response = await CommonRepository.tempLockBikeIdl(
        cancelToken: cancelToken,
        vid: vid,
        orderId: orderId,
        sw: sw,
    );
    EasyLoading.dismiss();
    if(response.statusCode == REQUEST_SUCCESS){
      if(sw == 1){
        bikeStatus.value = BikeStatus.tempLockSuccess;
        Future.delayed(const Duration(seconds: 1),(){
          bikeStatus.value = BikeStatus.tempLockCount;

          tempLockCountdownTime.value = 0;
          getUnPayInfo(orderId);
        });
      }else if(sw == 2){
        bikeStatus.value = BikeStatus.temUnLockSuccess;
        Future.delayed(const Duration(seconds: 1),(){
          bikeStatus.value = BikeStatus.riding;
          tempLockCountdownTime.value = 0;
          getUnPayInfo(orderId);
        });
      }
    }else{
      if(sw == 1){
        bikeStatus.value = BikeStatus.tempLockFailed;
      }else if(sw == 2){
        DioClient.showError(response);
      }
      tempLockBikeM = response;
    }
    return response;
  }

  Future returnBike(String vid,String orderId,{bool? skipParkingCheck}) async {
    bikeStatus.value = BikeStatus.backing;

    GoogleMapUtils.getCurrentPosition((position)async{
      final req = ReturnBikeReq(
        vid: vid,
        orderId: orderId,
        ut: position.latitude,
        ug: position.longitude,
        orderSpec: isOpenPrepayEndOrder == true ?1 :0,
        skipParkingCheck: skipParkingCheck == true?1:0,
      );
      final Response response = await CommonRepository.returnBikeIdl(
        cancelToken: cancelToken,
        req: req,
        isOpenPrepayEndOrder: isOpenPrepayEndOrder,
      );
      if(response.statusCode == REQUEST_SUCCESS){
        if(isOpenPrepayEndOrder){
          bikeStatus.value = BikeStatus.riding;
          state.showBacFeeDialog(Properties.fromJson(response.data), 6,req);
        }else{
          bikeStatus.value = BikeStatus.backSuccess;
          Future.delayed(const Duration(seconds: 1),(){
            if(state.mounted){
              state.navigatorToPay();
            }
          });
        }
      }else{
        bikeStatus.value = BikeStatus.backFailed;
        returnBikeM = response;
        state.showBackFailedDialog();
      }
    });
  }

  /// 先付款后还车查询骑行费用
  Future returnBikeQueryFee(String vid,String orderId,{bool? skipParkingCheck}) async {
    bikeStatus.value = BikeStatus.backing;
    GoogleMapUtils.getCurrentPosition((position)async{
      final Response response = await CommonRepository.returnBikeFeeIdl(
        cancelToken: cancelToken,
        vid: vid,
        orderId: orderId,
        lat: position.latitude,
        lng: position.longitude,
        skipParkingCheck: skipParkingCheck == true?1:0,
      );
      if(response.statusCode == REQUEST_SUCCESS){
        bikeStatus.value = BikeStatus.backSuccess;
        Future.delayed(const Duration(seconds: 1),(){
          if(state.mounted){
            state.navigatorToPay();
          }
        });
      }else{
        bikeStatus.value = BikeStatus.backFailed;
        returnBikeM = response;
        state.showBackFailedDialog();
      }
    });
  }

  final isCheckParking = ValueNotifier<bool>(false);
  Future<bool> checkParking(String vid) async {
    if(isCheckParking.value)return false;
    isCheckParking.value = true;
    EasyLoading.show(status: S.current.verifyLocation);
    final res = await CmdRepository.bikeRefreshGpsIdl(vid: vid);
    if(res != null){
      final result = await CommonRepository.checkParkingIdl(
          cancelToken: cancelToken,
          lat: res.latitude,
          lng: res.longitude
      );
      if(result != null && result.id != null){
        isCheckParking.value = false;
        EasyLoading.dismiss();
        return true;
      }
    }

    isCheckParking.value = false;
    return false;
  }



  Future<Response> helmetUnlock(String vid,String orderId) async {
    bikeStatus.value = BikeStatus.openHelmeting;
    final Response response = await CommonRepository.helmetUnlockIdl(
        cancelToken: cancelToken,
        vid: vid,
        orderId: orderId,
    );
    if(response.statusCode == REQUEST_SUCCESS){
      Future.delayed(const Duration(seconds: 1),()=>bikeStatus.value = BikeStatus.openHelmetSuccess);
    }else{
      bikeStatus.value = BikeStatus.openHelmetFailed;
      helmetUnlockM = response;
    }
    return response;
  }

  Future getBrandAreaInfo() async {
    final result =
        await CommonRepository.getBrandAreaInfoIdl(cancelToken: cancelToken);
    if (result != null) {
      AccountManager.areaInfoM = result;
      final mAreaPolygon = Polygon(
          polygonId: PolygonId('${result.brandCode}_${result.areaCode}'),
          fillColor: ColorStyles.color_1E88E5.withOpacity(0.2),
          points: result.operateAreaPoints,
          strokeWidth: 3,
          strokeColor: ColorStyles.color_1E88E5.withOpacity(0.8));
      areaPolygons = {mAreaPolygon};
    }
    state.notifyChange();
  }

  Future getBikeInfo(String vid) async {
    bikeInfoM = await CommonRepository.getBikeInfoIdl(
        cancelToken: cancelToken, vid: vid);
    if(bikeInfoM?.bikeInfo?.areaId != null && bikeInfoM!.bikeInfo!.areaId!.isNotEmpty){
      AccountManager.handleAreaCode(tBikeAreaCode: bikeInfoM?.bikeInfo?.areaId);
    }
    state.notifyChange();
  }

  Future getBikeRealTime(String vid) async {
    bikeRealTimeM = await CommonRepository.getBikeRealTimeIdl(
        cancelToken: cancelToken, vid: vid);
    state.notifyChange();
  }

  Future getUnPayInfo(String? orderId) async {
    unPayInfoM = await CommonRepository.getUnPayInfoIdl(
        cancelToken: cancelToken, orderId: orderId);
    if (unPayInfoM != null) {
      getServerTime();
    }
    state.notifyChange();
  }

  Future getNearbyBike({required num lat, required num lng}) async {
    if (isRequestingVehicle) {
      return;
    }
    isRequestingVehicle = true;
    final result = await CommonRepository
        .getNearbyBikeIdl(cancelToken: cancelToken, lat: lat, lng: lng);
    final icon = await BitmapDescriptor.fromAssetImage(
        devicePixelRatio, 'assets/common_v2/ic_map_bike.png',
        mipmaps: false);
    final mMarkers = result
        .map((e) => Marker(
              markerId: MarkerId(e.vid!),
              icon: icon,
              position: LatLng(e.lat!.toDouble(), e.lng!.toDouble()),
            ))
        .toList();
    markers = mMarkers.toSet();
    isRequestingVehicle = false;
    state.notifyChange();
  }

  /// 请求所有类型的站点
  /// [type] 站点类型 1，2，3
  void getAllNearbyPark(
      {required num lat,
      required num lng,
      List<int> type = const [1, 2, 3]}) async {
    SingleCall.call(() {
      for(var item in type) {
        getNearbyPark(lat: lat,lng: lng,type:item,reset: type.first == item);
      }
    });
  }

  /// [reset] 是否重置站点数据
  /// [type] 站点类型
  Future getNearbyPark(
      {required num lat,
      required num lng,
      required int type,
      required bool reset}) async {
    if (reset) {
      stationMarkers = {};
      stationPolygons = {};
    }
    final result = await CommonRepository
        .getNearbyParkIdl(cancelToken: cancelToken, lat: lat, lng: lng,type: type,isShowEmptyTip: type == 1);
    final Set<Polygon> mStationPolygon = {};
    final mMarkers = result.map((e) {
      if (e.polygonPoints != null && e.polygonPoints!.isNotEmpty) {
        mStationPolygon.add(Polygon(
          polygonId: PolygonId(e.id!),
          fillColor: Globals.stationFillColorMap[e.groupType!]!,
          points: e.polygonPoints!.first,
          strokeWidth: 2,
          strokeColor: Globals.stationStrokeColorMap[e.groupType!]!,
        ));
      }
      if (e.groupType == 1 || e.groupType == 3 || e.groupType == 4) {
        return Marker(
          markerId: MarkerId(e.id!),
          icon: forbidStationIcon,
          position: LatLng(e.lat!.toDouble(), e.lng!.toDouble()),
        );
      } else if (e.groupType == 2) {
        return Marker(
          markerId: MarkerId(e.id!),
          icon: noWaitStationIcon,
          position: LatLng(e.lat!.toDouble(), e.lng!.toDouble()),
        );
      } else {
        return Marker(
          markerId: MarkerId(e.id!),
          icon: normalStationIcon,
          position: LatLng(e.lat!.toDouble(), e.lng!.toDouble()),
        );
      }
    });
    stationMarkers.addAll(mMarkers.toSet());
    stationPolygons.addAll(mStationPolygon);

    state.notifyChange();
  }

  Future findBike(String vid) async {
    final result =  await CmdRepository.findBikeIdl(
        cancelToken: cancelToken, lat: AccountManager.userLatitude,lng:AccountManager.userLongitude,vid: vid);
    return result;
  }

  /// 请求数据
  @override
  Future<PageViewModel?> requestData({Map<String, dynamic>? params}) async {
    return null;
  }
}
